package com.demo2do.fms.admin.service.supplier.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.persistence.support.QueryFilter;
import com.demo2do.fms.admin.Constants;
import com.demo2do.fms.admin.dao.authority.BranchDao;
import com.demo2do.fms.admin.dao.authority.UserDao;
import com.demo2do.fms.admin.dao.supplier.DriverDao;
import com.demo2do.fms.admin.dao.supplier.OrganizationDao;
import com.demo2do.fms.admin.dao.supplier.SupplierDao;
import com.demo2do.fms.admin.dao.supplier.SupplierEventDao;
import com.demo2do.fms.admin.dao.supplier.SupplierProfileDao;
import com.demo2do.fms.admin.dao.supplier.SupplierRelationDao;
import com.demo2do.fms.admin.dao.supplier.SupplierSourceDao;
import com.demo2do.fms.admin.dao.vehicle.RemoteTransMeansDao;
import com.demo2do.fms.admin.dao.vehicle.TractorDao;
import com.demo2do.fms.admin.dao.vehicle.TrailerDao;
import com.demo2do.fms.admin.dao.vehicle.VehicleDao;
import com.demo2do.fms.admin.dao.vehicle.VehicleSourceDao;
import com.demo2do.fms.admin.entity.export.supplier.SupplierSheet;
import com.demo2do.fms.admin.entity.search.supplier.SubSupplierSearch;
import com.demo2do.fms.admin.entity.search.supplier.SupplierSearch;
import com.demo2do.fms.admin.entity.security.Login;
import com.demo2do.fms.admin.handler.VamHandler;
import com.demo2do.fms.admin.service.DataServiceImpl;
import com.demo2do.fms.admin.service.supplier.SupplierService;
import com.demo2do.fms.entity.authority.Branch;
import com.demo2do.fms.entity.authority.User;
import com.demo2do.fms.entity.driver.Dismiss;
import com.demo2do.fms.entity.driver.Driver;
import com.demo2do.fms.entity.driver.DriverAuditStatus;
import com.demo2do.fms.entity.supplier.SupplierSource;
import com.demo2do.fms.entity.supplier.common.AuditStatus;
import com.demo2do.fms.entity.supplier.common.Level;
import com.demo2do.fms.entity.supplier.common.Supplier;
import com.demo2do.fms.entity.supplier.common.SupplierCertificate;
import com.demo2do.fms.entity.supplier.common.SupplierEvent;
import com.demo2do.fms.entity.supplier.common.SupplierEventType;
import com.demo2do.fms.entity.supplier.common.SupplierInfo;
import com.demo2do.fms.entity.supplier.common.SupplierModifiedVersion;
import com.demo2do.fms.entity.supplier.common.SupplierRecommendation;
import com.demo2do.fms.entity.supplier.common.SupplierRelation;
import com.demo2do.fms.entity.supplier.common.Type;
import com.demo2do.fms.entity.supplier.trans.TransSupplier;
import com.demo2do.fms.entity.supplier.ware.WareSupplier;
import com.demo2do.fms.entity.vehicle.ModifiedStatus;
import com.demo2do.fms.entity.vehicle.source.LockStatus;
import com.demo2do.fms.entity.vehicle.source.LockType;
import com.demo2do.fms.entity.vehicle.source.RemoteTransMeans;
import com.demo2do.fms.entity.vehicle.source.Vehicle;
import com.demo2do.fms.entity.vehicle.source.VehicleSource;
import com.demo2do.fms.entity.vehicle.source.VehicleSourceLockRecord;
import com.demo2do.fms.entity.vehicle.tractor.Tractor;
import com.demo2do.fms.entity.vehicle.trailer.Trailer;

/**
 * 
 * @author Ysy
 *
 */
@Service("supplierService")
public class SupplierServiceImpl extends DataServiceImpl<Supplier> implements SupplierService{

    @Dao
    private SupplierDao supplierDao;
    
    @Dao
    private SupplierSourceDao supplierSourceDao;
    
    @Dao
    private SupplierProfileDao supplierProfileDao;
    
    @Dao
    private OrganizationDao organizationDao;
    
    @Dao
    private SupplierRelationDao supplierRelationDao;
    
    @Dao
    private UserDao userDao;
    
    @Dao
    private TractorDao tractorDao;
    
    @Dao
    private TrailerDao trailerDao;
    
    @Dao
    private VehicleSourceDao vehicleSourceDao;
    
    @Dao
    private VehicleDao vehicleDao;
    
    @Dao
    private DriverDao driverDao;
    
    @Dao
    private SupplierEventDao supplierEventDao;
    
    @Dao
    private RemoteTransMeansDao remoteTransMeansDao;
    
    @Autowired
    private VamHandler vamHandler;
    
    @Dao
    private BranchDao branchDao;
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#getSupplierRecommendation(java.lang.Long)
     */
    public SupplierRecommendation getSupplierRecommendation(Long supplierId) {
        return supplierProfileDao.getSupplierRecommendation(supplierId);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(java.util.List)
     */
    public List<Supplier> list(List<Long> ids) {
        return supplierDao.list(ids);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(com.demo2do.fms.entity.supplier.common.Type)
     */
    public List<Supplier> list(Type type, List<AuditStatus> status) {
        return supplierDao.list(type, status);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(com.demo2do.fms.entity.supplier.common.Type, java.util.List, com.demo2do.fms.admin.entity.security.Login)
     */
    public List<Supplier> list(Type type, List<AuditStatus> status, Login login) {
        
        if (login.isAdminUser() || login.isSuper()) {
            
            return supplierDao.list(type, status);
            
        } else if (login.isBranchUser()) {
            
            Branch branch = branchDao.load(login.getBranch());
            return supplierDao.list(type, status, branch);
            
        } else if (login.isSponsorUser() || login.isFmsUser()) {
            
            Supplier supplier = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            if (supplier.isSecond()) {
                return Collections.emptyList();
            }
            return supplierRelationDao.listSponsoredSupplier(supplier, type, status);
            
        } else {
            return Collections.emptyList();
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(com.demo2do.core.entity.page.Page)
     */
    public List<Supplier> list(Page page) {
        List<Supplier> result = supplierDao.list(page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return result;
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#obtain(java.lang.String, java.lang.String)
     */
    public List<SupplierSource> obtain(Type type, String code) {
        
        List<SupplierSource> suppliers = new ArrayList<SupplierSource>();
        
        // 1. 根据 'code or name' 校验supplier是否已经存在于本系统
        int countExist = supplierDao.count(code, type);
        if(countExist > 0) {
            throw BusinessException.newInstance("1", "该供方已存在，不能再引入");
        }

        // 2. check supplier whether exist mdm
        if(type.isMotor()) {			// 2.1 查询运输供方
            
            // returns TransSupplierSource
            suppliers = supplierSourceDao.listTransSupplier(code);
            
        } else if(type.isStorage()) { 	// 2.2 查询仓储供方
        
            // returns WareSupplierSource
            suppliers = supplierSourceDao.listWareSupplier(code);
        
        } else if (type.isCommonStorage()){  //查询一般仓储供方

            suppliers = supplierSourceDao.listCommonWareSupplierSource(code);
        }
        if(suppliers.isEmpty()) {
            throw BusinessException.newInstance("-1", "MDM中未查询到该代码，请先至MDM创建代码");
        }
        
        return suppliers;
        
    }

    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(com.demo2do.fms.entity.supplier.SupplierLevel)
     */
    public List<Supplier> list(Level supplierLevel) {
        return supplierDao.list(supplierLevel);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#list(com.demo2do.fms.entity.supplier.common.Level, com.demo2do.fms.entity.supplier.common.Type)
     */
    public List<Supplier> list(Level level, Type type) {
    	return supplierDao.list(level, type);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#export(com.demo2do.fms.admin.entity.search.supplier.SubSupplierSearch)
     */
    @SuppressWarnings("unchecked")
	public List<SupplierSheet> export(SubSupplierSearch search) {
    	
    	// 1. list suppliers
    	String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        List<Supplier> suppliers = genericDaoSupport.searchForList(sentence, parameters);
        
        // 2. transform suppliers to supplierSheet
        List<SupplierSheet> sheets = this.parseSupplierSheet(suppliers);
    	return sheets;
    	
    }
    
    /**
     * @param suppliers
     * @return
     */
    private List<SupplierSheet> parseSupplierSheet(List<Supplier> suppliers) {
    	
    	List<SupplierSheet> sheets = new ArrayList<SupplierSheet>();
    	for (Supplier supplier : suppliers) {
		
    		SupplierInfo supplierInfo = supplierDao.loadSupplierInfo(supplier);
    		
    		SupplierSheet supplierSheet = new SupplierSheet(supplier, supplierInfo);
    		sheets.add(supplierSheet);
    		
		}
    	
    	return sheets;
    	
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#create(com.demo2do.fms.entity.supplier.common.Supplier, java.util.List, java.lang.Long)
     */
    public void create(Supplier supplier, Long parentId, Long operator) {
        
    	// 0. validate
    	int exists = supplierDao.count(supplier.getCode(), supplier.getType());
    	if (exists > 0) {
    		throw BusinessException.newInstance("400", "该供方已存在，不能再引入");
    	}
    	
    	// 1. create supplier
    	genericDaoSupport.save(supplier.initliaze(operator));
    	
    	// 2. create supplier relation when supplier is second supplier
    	if (!supplier.isFirst()) {
			Supplier parent = genericDaoSupport.load(Supplier.class, parentId);
			SupplierRelation relation = new SupplierRelation(parent, supplier); 
			genericDaoSupport.save(relation);
    	}
        
        // 3. create empty supplier_certificate
        genericDaoSupport.save(new SupplierCertificate(supplier, operator));
        
        // 4. create empty supplier_info
        genericDaoSupport.save(new SupplierInfo(supplier, operator));
        
        // 5. create empty supplierRecommendation
        genericDaoSupport.save(new SupplierRecommendation(supplier, operator));
        
        // 6. according the supplier's type to create empty transSupplier or wareSupplier
        Type type = supplier.getType();
        if (type.isMotor()) {
            genericDaoSupport.save(new TransSupplier(supplier).initialize(operator));
        } else if (type.isStorage()) {
            genericDaoSupport.save(new WareSupplier(supplier).initialize(operator));
        }
        
        // 7. save supplier event
        genericDaoSupport.save(new SupplierEvent(supplier, SupplierEventType.CREATE, operator));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#countSubSupplier(com.demo2do.fms.admin.entity.search.supplier.SubSupplierSearch)
     */
    public int countSubSupplier(SubSupplierSearch search) {
    	
    	String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        return genericDaoSupport.count(sentence, parameters);
    	
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#rectify(com.demo2do.fms.entity.supplier.common.Supplier, com.demo2do.fms.entity.supplier.common.AuditStatus, java.lang.Long)
     */
    public void rectify(Supplier supplier, AuditStatus status, Long operator) {
        genericDaoSupport.update(supplier.rectify(status, new Date(), operator));
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#changeLevel(com.demo2do.fms.entity.supplier.common.Supplier, java.util.List, java.lang.Long)
     */
    public void changeLevel(Supplier supplier, List<Long> parents, Long operator) {
    	
    	Date now = new Date();
    	
    	if (supplier.isFirst()) {			// 一级供应商变更为二级供应商
    		
    		if (CollectionUtils.isEmpty(parents)) {
    			throw BusinessException.newInstance("400", "请选择挂靠管理公司");
    		}
    		
    		// check parent is self
    		if (parents.contains(supplier.getId())) {
    		    throw BusinessException.newInstance("400", "挂靠管理公司不允许为本公司");
    		}
    		
    		// 1.1 delete before supplier relation
    		List<SupplierRelation> relations = supplierRelationDao.listSubRelation(supplier);
    		if (CollectionUtils.isNotEmpty(relations)) {
    			throw BusinessException.newInstance("400", "请先处理该供方下所属二级供应商");
    		}
        	
        	// 1.2 create new supplier relation
    		for (Long parentId : parents) {
				
    			Supplier parent = genericDaoSupport.load(Supplier.class, parentId);
    			SupplierRelation relation = new SupplierRelation(parent, supplier); 
    					
    			genericDaoSupport.save(relation);
    			
			}
    		
    		// 1.3 delete user
    		List<User> users = userDao.list(supplier.getId());
    		for (User user : users) {
				genericDaoSupport.update(user.disable().operator(operator, now));
			}
        	
        	// 1.4 update supplier
    		genericDaoSupport.update(supplier.changeLevel(Level.SECOND).operate(now, operator));
    		
    	} else {							// 二级供应商变更为一级供方商
    		
    		// 2.1 delete before supplier relation
    		List<SupplierRelation> relations = supplierRelationDao.list(supplier);
    		for (SupplierRelation relation : relations) {
				genericDaoSupport.update(relation.disable());
			}
    		
    		// 2.2 delete user
    		List<User> users = userDao.list(supplier.getId());
    		for (User user : users) {
				genericDaoSupport.update(user.disable().operator(operator, now));
			}
        	
        	// 2.3 update supplier
    		genericDaoSupport.update(supplier.changeLevel(Level.FIRST).operate(now, operator));
    		
    	}
    	
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#changeParent(com.demo2do.fms.entity.supplier.common.Supplier, java.util.List, java.lang.Long)
     */
    public void changeParent(Supplier supplier, List<Long> parents, Long operator) {
    	
    	// 1. delete supplier before relation
    	List<SupplierRelation> relations = supplierRelationDao.list(supplier);
    	for (SupplierRelation relation : relations) {
			genericDaoSupport.save(relation.disable());
		}
    	
    	// 2. create new relation
    	for (Long parentId : parents) {
    		
    		Supplier parent = genericDaoSupport.load(Supplier.class, parentId);
			SupplierRelation relation = new SupplierRelation(parent, supplier); 
					
			genericDaoSupport.save(relation);
    		
    	}
    	
    	// 3. update supplier operate
    	genericDaoSupport.update(supplier.operate(new Date(), operator));
    	
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#changeBranch(com.demo2do.fms.entity.supplier.common.Supplier, com.demo2do.fms.entity.authority.Branch, java.lang.Long)
     */
    public void changeBranch(Supplier supplier, Branch branch, Long operator) {
    	genericDaoSupport.update(supplier.changeBranch(branch, operator));
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#syncShortname(com.demo2do.fms.entity.supplier.common.Supplier, java.lang.Long)
     */
    public void syncShortname(Supplier supplier, Long operator) {
        
        Type type = supplier.getType();
        
        if (type.isMotor()) {               // 运输供方
            
            SupplierSource supplierSource = supplierSourceDao.loadTransSupplier(supplier.getCode());
            genericDaoSupport.update(supplier.editShortname(supplierSource.getShortName(), operator));
            
        } else if (type.isStorage() || type.isCommonStorage()) {      // 仓储供方 或一般供方
            
            SupplierSource supplierSource = supplierSourceDao.loadWareSupplier(supplier.getCode());
            genericDaoSupport.update(supplier.editShortname(supplierSource.getShortName(), operator));
            
        } else {
            throw BusinessException.newInstance("500", "供方类型不对");
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#delete(com.demo2do.fms.entity.supplier.common.Supplier, java.lang.Long)
     */
    public void delete(Supplier supplier, Long operator) {
        
        // 0. validate
        this.checkDeleteSupplier(supplier);
        
        // 1. delete vehicle
        this.deleteVehicle(supplier, operator);
        
        // 2. delete driver
        this.deleteDriver(supplier, operator);
        
        // 3. delete user
        this.deleteUser(supplier, operator);

        // 4. delete supplier
        this.deleteSupplier(supplier, operator);
        
    }
    
    /**
     * @param supplier
     */
    private void checkDeleteSupplier(Supplier supplier) {
        if (supplier.isFirst()) {
            int count = supplierRelationDao.countSponsoredSupplier(supplier);
            if (count > 0) {
                throw BusinessException.newInstance("500", "该供方有二级供方挂靠，无法删除");
            }
        }
    }
    
    /**
     * @param supplier
     * @param operator
     */
    private void deleteVehicle(Supplier supplier, Long operator) {
        
        // 1. 删除牵引车
        List<Tractor> tractors = tractorDao.list(supplier);
        for (Tractor tractor : tractors) {
            if (tractor.isSynchronize()) {
                genericDaoSupport.update(tractor.out(operator));
            } else {
                genericDaoSupport.update(tractor.disable(operator));
            }
        }
        
        // 2. 删除挂车
        List<Trailer> trailers = trailerDao.list(supplier);
        for (Trailer trailer : trailers) {
            if (trailer.isSynchronize()) {
                genericDaoSupport.update(trailer.out(operator));
            } else {
                genericDaoSupport.update(trailer.disable(operator));
            }
        }
        
        // 3. 删除整车
        List<VehicleSource> vehicleSources = vehicleSourceDao.list(supplier);
        for (VehicleSource vehicleSource : vehicleSources) {
            if (vehicleSource.isSynchronize()) {
                
                // 3.1 lock vehicle
                this.lockVehicle(vehicleSource, "删除供方，整车冻结", LockType.FREEZE, operator, "转出冻结");
                
                // 3.2 unbind driver
                Vehicle vehicle = vehicleDao.loadByCode(vehicleSource.getCode());
                if(vehicle != null) {
                    List<Driver> drivers = driverDao.listByVehicle(vehicle.getId(), DriverAuditStatus.QUALIFIED);
                    for(Driver driver : drivers) {
                        genericDaoSupport.update(driver.unbind(operator, new Date()));
                    }
                }
                
                // 3.3 out vehicle
                genericDaoSupport.update(vehicleSource.out(operator));
                
            } else {
                genericDaoSupport.update(vehicleSource.disable(operator));
            }
        }
        
    }
    
    /**
     * @param vehicleSource
     * @param reason
     * @param type
     * @param operator
     * @param description
     * @return
     */
    private VehicleSource lockVehicle(VehicleSource vehicleSource, String reason, LockType type, Long operator, String description) {
        
        Date now = new Date();
        
        // 1. 锁定FMS车辆
        genericDaoSupport.update(vehicleSource.doLock(reason, type, operator, now));
        
        String vehicleCode = vehicleSource.getCode();
        RemoteTransMeans remoteTransMeans = remoteTransMeansDao.loadByCode(vehicleCode);
        
        if(remoteTransMeans == null) {
            throw new BusinessException("锁车数据信息为空");
        }
        if(!remoteTransMeans.isAvaliable()) {
            throw new BusinessException("MDM中该车辆为非正常车辆");
        }
        
        // 2. 锁定MDM车辆
        genericDaoSupport.update(remoteTransMeans.lock(type, Constants.MDM_LOCK_USERID));
        
        // 3. 创建锁车记录
        VehicleSourceLockRecord record = new VehicleSourceLockRecord(vehicleSource, LockStatus.LOCKED, description, operator);
        genericDaoSupport.save(record);
        
        return vehicleSource;
        
    }
    
    /**
     * @param supplier
     * @param operator
     */
    private void deleteDriver(Supplier supplier, Long operator) {
        
        List<Driver> drivers = driverDao.list(supplier);
        for (Driver driver : drivers) {
            
            if (driver.getStatus().isQualified()) {     // 离职
                
                // 1. update driver dismiss info
                genericDaoSupport.update(driver.quit(operator));
                
                // 2. construct dismiss and save to database
                Dismiss dismiss = new Dismiss(driver.getName(), driver.getCitizenCode(), new Date());
                genericDaoSupport.save(dismiss);
                
            } else {                                    // 删除
                genericDaoSupport.update(driver.disable(operator));
            }
            
        }
        
    }
    
    /**
     * @param supplier
     * @param operator
     */
    private void deleteUser(Supplier supplier, Long operator) {
        
        List<User> users = userDao.list(supplier.getId());
        for (User user : users) {
            
            // 1. delete user
            genericDaoSupport.update(user.disable().operator(operator, new Date()));
            
            // 2. sync vam
            if (user.isVam()) {
                vamHandler.edit(user);
            }
            
        }
        
    }
    
    /**
     * @param supplier
     * @param operator
     */
    private void deleteSupplier(Supplier supplier, Long operator) {
        
        Long supplierId = supplier.getId();
        
        // 1. according the supplier's type to delete  transSupplier or wareSupplier
        Type type = supplier.getType();
        if (type.isMotor()) {
            TransSupplier transSupplier = supplierProfileDao.getTransSupplier(supplierId);
            genericDaoSupport.update(transSupplier.disable(operator));
        } else if (type.isStorage()) {
            WareSupplier wareSupplier = supplierProfileDao.getWareSupplier(supplierId);
            genericDaoSupport.update(wareSupplier.disable(operator));
        }
        
        // 3. delete supplierRecommendation
        SupplierRecommendation recommendation = supplierProfileDao.getSupplierRecommendation(supplierId);
        genericDaoSupport.update(recommendation.disable(operator));
        
        // 4. delete supplier_info
        SupplierInfo supplierInfo = supplierProfileDao.getSupplierInfo(supplierId);
        genericDaoSupport.update(supplierInfo.disable(operator));
        
        // 5. delete supplier_certificate
        SupplierCertificate supplierCertificate = supplierProfileDao.getSupplierCertificate(supplierId);
        genericDaoSupport.update(supplierCertificate.disable(operator));
        
        // 6. delete supplier_relation when supplier is not first_supplier
        if (supplier.isFirst()) {
            supplierRelationDao.deleteByParent(supplier);
        } else {
            supplierRelationDao.deleteByChild(supplier);  
        }
        
        // 7. delete supplier
        genericDaoSupport.update(supplier.disable(operator));
        
        // 8. save supplier_event
        genericDaoSupport.save(new SupplierEvent(supplier, SupplierEventType.DELETE, operator));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#countSponsoredSupplier(com.demo2do.fms.entity.supplier.Supplier)
     */
    public int countSponsoredSupplier(Supplier parent) {
        return supplierRelationDao.countSponsoredSupplier(parent);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#countRectifySupplier(com.demo2do.fms.admin.entity.security.Login)
     */
    public int countRectifySupplier(Login login) {
        
        AuditStatus[] status = new AuditStatus[]{AuditStatus.QUALIFIED, AuditStatus.ONE_LEVEL_RECTIFY, AuditStatus.TWO_LEVEL_RECTIFY, AuditStatus.UNITE_RECTIFY};
        
        if (!login.isSupplier()) {      // 非供方，查询所有
            return supplierDao.countSupplierByStatus(Type.MOTOR, status);
        } else {                        // 一级供方，查询下属二级供方
        	Supplier parent = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            return supplierRelationDao.countSupplierByStatus(parent, status, Type.MOTOR);
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#countRectify(com.demo2do.fms.admin.entity.search.supplier.SupplierSearch)
     */
    public int countRectify(SupplierSearch search) {
        
        AuditStatus[] status = new AuditStatus[]{AuditStatus.QUALIFIED, AuditStatus.ONE_LEVEL_RECTIFY, AuditStatus.TWO_LEVEL_RECTIFY, AuditStatus.UNITE_RECTIFY};
        search.addStatus(status);
        
        // 1. build sentence
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        // 2. do query
        return genericDaoSupport.count(sentence, parameters);
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listRectifySupplier(com.demo2do.fms.admin.entity.security.Login, com.demo2do.core.entity.page.Page)
     */
    public List<Supplier> listRectifySupplier(Login login, Page page) {
        
        AuditStatus[] status = new AuditStatus[]{AuditStatus.QUALIFIED, AuditStatus.ONE_LEVEL_RECTIFY, AuditStatus.TWO_LEVEL_RECTIFY, AuditStatus.UNITE_RECTIFY};
        page.calculate();
        
        if (!login.isSupplier()) {      // 非供方，查询所有
            return supplierDao.listSupplierByPage(Type.MOTOR, status, page.getBeginIndex(), page.getEveryPage());
        } else {                        // 一级供方， 查询下属二级供方
        	Supplier parent = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            return supplierRelationDao.listSupplierByPage(parent, Type.MOTOR, status, page.getBeginIndex(), page.getEveryPage());
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listRectiry(com.demo2do.fms.admin.entity.search.supplier.SupplierSearch, com.demo2do.core.entity.page.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Supplier> listRectify(SupplierSearch search, Page page) {
        
        AuditStatus[] status = new AuditStatus[]{AuditStatus.QUALIFIED, AuditStatus.ONE_LEVEL_RECTIFY, AuditStatus.TWO_LEVEL_RECTIFY, AuditStatus.UNITE_RECTIFY};
        search.addStatus(status);
        
        // 1. build sentence
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        // 2. do query
        List<Supplier> suppliers = genericDaoSupport.searchForList(sentence, parameters, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return suppliers;
        
    }

    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSponsoredSupplier(com.demo2do.fms.entity.supplier.common.Supplier)
     */
    public List<Supplier> listSponsoredSupplier(Supplier parent) {
        return supplierRelationDao.listSponsoredSupplier(parent);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSponsoredSupplierId(com.demo2do.fms.entity.supplier.common.Supplier)
     */
    public List<Long> listSponsoredSupplierId(Supplier parent) {
        return supplierRelationDao.listSponsoredSupplierId(parent);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSponsoredSupplierId(java.lang.String, java.lang.String)
     */
    @SuppressWarnings("unchecked")
    public List<Long> listSponsoredSupplierId(String parentCode, String parentName) {
        
        String sentence = "SELECT r.supplier.id FROM SupplierRelation r WHERE r.disabled = false";
        
        QueryFilter queryFilter = new QueryFilter();
        queryFilter.addSentence("r.parent.code = :parentCode", "parentCode", parentCode);
        if (StringUtils.isNotBlank(parentName)){
            queryFilter.addSentence("r.parent.name LIKE :parentName", "parentName", "%" + parentName + "%");
        }
        return genericDaoSupport.searchForList(sentence + queryFilter.clauseSentence(), queryFilter.parameters());
        
    }

    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSponsoredSupplier(com.demo2do.fms.entity.supplier.Supplier, com.demo2do.core.entity.page.Page)
     */
    public List<Supplier> listSponsoredSupplier(Supplier parent, Page page) {
        List<Supplier> suppliers = supplierRelationDao.listSponsoredSupplier(parent, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return suppliers;
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listParentSupplier(com.demo2do.fms.entity.supplier.common.Supplier)
     */
    public List<Supplier> listParentSupplier(Supplier supplier) {
    	return supplierRelationDao.listParentSupplier(supplier);
    }

    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSubSupplier(com.demo2do.fms.admin.entity.security.Login)
     */
    public List<Supplier> listSubSupplier(Login login) {
        
        if (!login.isSupplier()) {
            return supplierDao.list();
        } else {
        	Supplier parent = genericDaoSupport.load(Supplier.class, login.getSupplierId());
        	return supplierRelationDao.listSponsoredSupplier(parent);
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSubSupplier(com.demo2do.fms.admin.entity.security.Login, com.demo2do.fms.entity.supplier.common.Type)
     */
    public List<Supplier> listSubSupplier(Login login, Type type) {
        
        if (!login.isSupplier()) {
            return supplierDao.list(type);
        } else {
            Supplier parent = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            return supplierRelationDao.listSponsoredSupplier(parent, type);
        }
        
    }

    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSubSuppliers(com.demo2do.fms.admin.entity.security.Login, com.demo2do.core.entity.page.Page)
     */
    public List<Supplier> listSubSupplier(Login login, Page page) {
        
        List<Supplier> result = null;
        
        if(!login.isSupplier()){

            result = supplierDao.list(page.getBeginIndex(), page.getEveryPage());
            page.calculate();
            return result;

        } else{

        	Supplier supplier = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            result = supplierRelationDao.listSponsoredSupplier(supplier, page.getBeginIndex(), page.getEveryPage());
            page.calculate();
            return result;
            
        }
        
    }

    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#getSupplierEvent(java.lang.Long, com.demo2do.fms.entity.supplier.common.SupplierEventType)
     */
    public SupplierEvent getSupplierEvent(Long supplierId, SupplierEventType type) {
         return supplierEventDao.get(supplierId, type);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSubSupplierIds(com.demo2do.fms.admin.entity.security.Login)
     */
    public List<Long> listSubSupplierId(Login login) {

        if (!login.isSupplier()) {
            return supplierDao.listSupplierIds();
        } else {
        	Supplier supplier = genericDaoSupport.load(Supplier.class, login.getSupplierId());
            return supplierRelationDao.listSponsoredSupplierId(supplier);
        }

    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#listSupplier(com.demo2do.fms.admin.entity.search.supplier.SupplierSearch)
     */
    @SuppressWarnings("unchecked")
    public List<Supplier> listSupplier(SupplierSearch search) {
        
        // 1. build sentence
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        // 2. do query
        List<Supplier> suppliers = genericDaoSupport.searchForList(sentence, parameters);
        return suppliers;
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.SupplierService#getSupplierModifiedVersion(com.demo2do.fms.entity.supplier.common.Supplier)
     */
    public SupplierModifiedVersion getSupplierModifiedVersion(Supplier supplier) {
        return supplierDao.loadModifiedVersion(supplier.getId(), ModifiedStatus.AUDITING);
    }
}
